package cn.buk.api.ctrip.service;

import cn.buk.api.ctrip.dto.ApiOpResult;
import cn.buk.api.ctrip.dto.SearchPolicyCriteria;
import cn.buk.common.Constant;
import cn.buk.common.JsonResult;
import cn.buk.util.DateUtil;
import cn.buk.util.XmlUtil;
import com.ctrip.openapi.java.base.HttpAccessAdapter;
import com.ctrip.openapi.java.utils.SignatureUtils;
import ctrip.api.flight.trade.common.basetype.v1.*;
import ctrip.api.flight.trade.common.commondata.v1.DCityACityType;
import ctrip.api.flight.trade.common.commondata.v1.FdPolicySearchRequestType;
import ctrip.api.flight.trade.common.commondata.v1.FdPolicySearchResponseType;
import ctrip.api.flight.trade.message.lowpricepolicy.v1.*;
import ctrip.api.flight.trade.message.patafailpolicy.v1.PataSummarySearchConditionType;
import ctrip.api.flight.trade.message.patafailpolicy.v1.PataSummarySearchRequestType;
import ctrip.api.flight.trade.message.patafailpolicy.v1.PataSummarySearchResponseType;
import ctrip.api.flight.trade.message.rawpolicy.v1.*;
import ctrip.api.flight.trade.message.specialpolicy.v1.*;
import org.apache.log4j.Logger;

import javax.xml.bind.*;
import javax.xml.datatype.XMLGregorianCalendar;
import java.io.StringReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * Created by william on 2015-8-17.
 *

 自2016年1月8日起，针对QuickAPI流量限制优化，具体内容如下：



 1、普通政策和特殊政策：

 【单程/往返】
 新增：20次/10秒
 全部删除：1次/30秒
 通过ID删除：5次/10秒
 通过政策代码删除：5次/10秒
 通过政策代码模糊删除：1次/10秒
 通过ExternalID删除：5次/10秒
 修改：5次/10秒
 修改价格：10次/10秒
 批量修改：5次/10秒
 概要查询（查询条件不包含机场、政策代码、政策ID)：2次/60秒

 2、低价查询：
 【单程】
 界面实时查询：12次/60秒
 界面缓存查询：2000次/60秒
 接口实时查询：100次/60秒
 接口缓存查询：2000次/60秒
 【往返】
 界面查询：12次/60秒
 接口查询：100次/60秒

 3、其他接口：20次/60秒

 ● IP限制：

 供应商的限制 * 50
 */
public class CtripTradeQuickApiServiceImpl implements CtripTradeQuickApiService {

    private static Logger logger = Logger.getLogger(CtripTradeQuickApiServiceImpl.class);


    private static final String API_CommonPolicyIDList = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/CommonPolicyIDList";
    private static final String API_CommonPolicySummary = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/CommonPolicySummary";
    private static final String API_CommonPolicyChangePrice = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/CommonPolicyChangePrice";
    private static final String API_CommonPolicyDelete = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/CommonPolicyDelete";

    private static final String API_SpecialPolicyIDList = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/SpecialPolicyIDList";
    private static final String API_SpecialPolicySummary = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/SpecialPolicySummary";
    private static final String API_SpecialPolicyDetail = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/SpecialPolicyDetailSearch";

    private static final String API_SpecialPolicyAdd = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/SpecialPolicyAdd";

    private static final String API_SpecialPolicyChange = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/SpecialPolicyChange";
    private static final String API_SpecialPolicyChangePrice = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/SpecialPolicyChangePrice";
    private static final String API_SpecialPolicyDelete = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/SpecialPolicyDelete";

    private static final String API_PataSummarySearch = "http://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/PataSummarySearch";


    private static final String API_FdPolicySearch = "http://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/FdPolicySearch";

    /**
     * 3.4.1	低价政策列表查询
     */
    //private static String API_LowPricePolicyList = "https://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/LowPricePolicyList";
    private static String API_LowPricePolicyList = "http://apiproxy.ctrip.com/apiproxy/soa2/11576/xml/LowPricePolicyList";
    private static String API_LowPricePolicyRoundTripList = "http://apiproxy.ctrip.com/apiproxy/soa2/11576/xml/LowPricePolicyRoundTripList";
    private static String API_LowPricePolicyList_Json = "http://apiproxy.ctrip.com/apiproxy/soa2/11576/json/LowPricePolicyList";
    private static String API_LowPricePolicyRoundTripList_Json = "http://apiproxy.ctrip.com/apiproxy/soa2/11576/json/LowPricePolicyRoundTripList";


    private final boolean outputXml;

    public CtripTradeQuickApiServiceImpl() {
        this.outputXml = false;
    }

    public CtripTradeQuickApiServiceImpl(boolean outputXml) {
        this.outputXml = outputXml;
    }

    private UserTokenType createUserInfo(final String username, final String password, final String md5password0) {
        UserTokenType userInfo = new UserTokenType();

        String md5password;

        if (md5password0 == null || md5password0.length() != 32)
            md5password = SignatureUtils.MD5(username + "#" + password);
        else
            md5password = md5password0;

        userInfo.setUserName(username);
        userInfo.setPassword(md5password);

        return userInfo;
    }

    /**
     * 根据tbooking username & password 创建MessageHeadType
     * @param username
     * @param password
     * @return
     */
    private MessageHeadType createMessageHeadType(final String username, final String password, final String md5password) {
        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        String requestGUID = UUID.randomUUID().toString();
        messageHead.setRequestGUID(requestGUID);
        return messageHead;
    }


    /**
     * 3.1.4	普通政策概要信息查询
     * @return
     */
    private String doSearchCommonPolicySummary(final String username, final String password, final String md5password, SearchPolicyCriteria sc) {
        CommonPolicySummaryRequestType request = new CommonPolicySummaryRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));

        request.setMessageHead(messageHead);

        CommonPolicySummaryRequestType.MessageBody messageBody = new CommonPolicySummaryRequestType.MessageBody();
        request.setMessageBody(messageBody);
        request.getMessageBody().setStartIndex(sc.getStartIndex());
        request.getMessageBody().setPageSize(sc.getPageSize());
        request.getMessageBody().setSearchType(SummarySearchType.BY_CONDITION);

        CommonPolicySearchConditionType searchConditionType = new CommonPolicySearchConditionType();
        request.getMessageBody().setSearchCondition(searchConditionType);

        searchConditionType.setFlightWay(FlightWaySType.S);
        if (sc.getDeparturePort().length() == 3) searchConditionType.setDepartPort(sc.getDeparturePort());
        if (sc.getArrivalPort().length() == 3) searchConditionType.setArrivePort(sc.getArrivalPort());
        if (sc.getCarrier().length() == 2) searchConditionType.setAirLine(sc.getCarrier());
        if (sc.getSubClass().length() > 0) searchConditionType.setSubClass(sc.getSubClass());



        String result = convertToXml(request, CommonPolicySummaryRequestType.class);
        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(result, API_CommonPolicySummary, null);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        return responseXml;
    }

    private String doSearchSpecialPolicySummary(final String username, final String password, final String md5password, SearchPolicyCriteria sc) {
        SpecialPolicySummaryRequestType request = new SpecialPolicySummaryRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));

        request.setMessageHead(messageHead);

        SpecialPolicySummaryRequestType.MessageBody messageBody = new SpecialPolicySummaryRequestType.MessageBody();
        request.setMessageBody(messageBody);

        messageBody.setStartIndex(sc.getStartIndex());
        messageBody.setPageSize(sc.getPageSize());

        messageBody.setSearchType(SummarySearchType.BY_CONDITION);
        SpecialPolicySearchConditionType searchConditionType = new SpecialPolicySearchConditionType();
        messageBody.setSearchCondition(searchConditionType);

        if (sc.getPolicyCode() != null) {
            searchConditionType.setPolicyCode(sc.getPolicyCode());
            searchConditionType.setIsFuzzyMatch(IsValidType.T);
        }



        if (sc.getPolicyCode() == null || sc.getPolicyCode().length() == 0) {
            searchConditionType.setFlightWay(FlightWaySType.S);
            if (sc.getDeparturePort().length() == 3) searchConditionType.setDepartPort(sc.getDeparturePort());
            if (sc.getArrivalPort().length() == 3) searchConditionType.setArrivePort(sc.getArrivalPort());
            if (sc.getCarrier().length() == 2) searchConditionType.setAirLine(sc.getCarrier());
            if (sc.getSubClass().length() > 0) searchConditionType.setGoSubClass(sc.getSubClass());
            //if (sc.getFlightNo().length() > 0) searchConditionType.setF
            if (sc.getDepartureDate() != null) {
                searchConditionType.setGoFlighteffectDate(DateUtil.convertDateToXMLGregorianCalendar(sc.getDepartureDate()));
                searchConditionType.setGoFlightexpiryDate(DateUtil.convertDateToXMLGregorianCalendar(sc.getDepartureDate()));
            }
        } else {
            //按照政策代码查询
            searchConditionType.setPolicyCode(sc.getPolicyCode());
        }


        String requestXml = convertToXml(request, SpecialPolicySummaryRequestType.class);



        //logger.info(requestXml);
        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_SpecialPolicySummary, null);

        if (this.outputXml) {
            System.out.println(requestXml);
            System.out.println(responseXml);
        }


        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        return responseXml;
    }

    /**
     * 3.1.3	普通政策概要信息查询
     * @return
     */
    public CommonPolicySummaryResponseType searchCommonPolicySummary(final String username, final String password, final String md5password, SearchPolicyCriteria sc) {
        String responseXml =  doSearchCommonPolicySummary(username, password, md5password, sc);
        return convertXmlTo(responseXml, CommonPolicySummaryResponseType.class);
    }

    private <T> String convertToXml(Object obj, Class<T> c) {

        return XmlUtil.convertToXml(obj, c);
    }

    public List<Long> searchSpecialPolicyIdList(final String username, final String password, final String md5password, final int maxRow) {
        List<Long> idList = new ArrayList<>();

        SpecialPolicyIDListRequestType request = new SpecialPolicyIDListRequestType();
        request.setMessageHead(createMessageHeadType(username, password, md5password));

        SpecialPolicyIDListRequestType.MessageBody messageBody = new SpecialPolicyIDListRequestType.MessageBody();
        request.setMessageBody(messageBody);
        request.getMessageBody().setSearchType(IDListSearchType.BY_CONDITION);
        request.getMessageBody().setStartIndex(0);
        request.getMessageBody().setPageSize(maxRow);

        String result = convertToXml(request, SpecialPolicyIDListRequestType.class);

        String responseXml = HttpAccessAdapter.SendTradeQuickApiRequest(result, API_SpecialPolicyIDList, null);
        int idx = responseXml.indexOf("<");
        if (idx > 0)
            responseXml = responseXml.substring(idx);

        SpecialPolicyIDListResponseType response = convertXmlTo(responseXml, SpecialPolicyIDListResponseType.class);

        if (response.getTradeResult().getErrorList().getError().size() > 0) {
            for(TradeErrorType errorType: response.getTradeResult().getErrorList().getError())
                logger.warn("ErrorCode: " + errorType.getErrorCode() + ", ErrorMsg: " + errorType.getErrorMessage());
        }

        int total = response.getTradeResult().getSearchResult().getTotalCount();
        if (total > 0) {
            for (PolicySearchType policy : response.getTradeResult().getSearchResult().getPolicyList().getPolicy())
                idList.add(policy.getID());
        }

        return idList;
    }

    /**
     * 根据查询条件，查找特殊政策的id列表; 如果有政策代码，则会精确匹配
     */
    public List<Long> searchSpecialPolicyIdList(final String username, final String password, final String md5password, SearchPolicyCriteria sc) {
        List<Long> idList = new ArrayList<>();

        SpecialPolicyIDListRequestType request = new SpecialPolicyIDListRequestType();
        request.setMessageHead(createMessageHeadType(username, password, md5password));

        SpecialPolicyIDListRequestType.MessageBody messageBody = new SpecialPolicyIDListRequestType.MessageBody();
        request.setMessageBody(messageBody);

        messageBody.setStartIndex(sc.getStartIndex());
        messageBody.setPageSize(sc.getPageSize());

        if (sc.getPolicyCode() != null) {
            messageBody.setSearchType(IDListSearchType.BY_CODE);
            messageBody.setPolicyCode(sc.getPolicyCode());
        } else {
            messageBody.setSearchType(IDListSearchType.BY_CONDITION);

            SpecialPolicySearchConditionType specialPolicySearchConditionType = new SpecialPolicySearchConditionType();
            messageBody.setSearchCondition(specialPolicySearchConditionType);
        }

        String requestXml = convertToXml(request, SpecialPolicyIDListRequestType.class);
        if (this.outputXml) System.out.println(requestXml);

        String responseXml = HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_SpecialPolicyIDList, null);
        int idx = responseXml.indexOf("<");
        if (idx > 0)
            responseXml = responseXml.substring(idx);

        if (this.outputXml) System.out.println(responseXml);

        SpecialPolicyIDListResponseType response = convertXmlTo(responseXml, SpecialPolicyIDListResponseType.class);

        if (response.getTradeResult().getErrorList().getError().size() > 0) {
            for(TradeErrorType errorType: response.getTradeResult().getErrorList().getError())
                logger.warn("ErrorCode: " + errorType.getErrorCode() + ", ErrorMsg: " + errorType.getErrorMessage());
        }

        int total = response.getTradeResult().getSearchResult().getTotalCount();
        if (total > 0) {
            for (PolicySearchType policy : response.getTradeResult().getSearchResult().getPolicyList().getPolicy())
                idList.add(policy.getID());
        }

        return idList;
    }


    /**
     * 3.2.3	特殊政策概要信息查询
     * 概要信息查询目前提供一次查询最多1000条记录。
     * 政策代码可以模糊匹配
     * @return
     */
    public SpecialPolicySummaryResponseType searchSpecialPolicySummary(final String username, final String password, final String md5password, SearchPolicyCriteria sc) {
        String responseXml = doSearchSpecialPolicySummary(username, password, md5password, sc);
        return convertXmlTo(responseXml, SpecialPolicySummaryResponseType.class);
    }

    /**
     * 3.2.5	特殊政策详细信息查询请求
     * 详细信息查询适合在修改数据前获取当前政策的详细信息进行确认。目前提供一次查询最多1000条记录。
     * @return
     */
    public SpecialPolicyDetailSearchResponseType searchSpecialPolicyDetail(final String username, final String password, final String md5password, final long policyId) {
        SpecialPolicyDetailSearchRequestType request = new SpecialPolicyDetailSearchRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        request.setMessageHead(messageHead);

        PolicyIDListType messageBody = new PolicyIDListType();
        request.setMessageBody(messageBody);

        messageBody.setPolicyIDList(new PolicyIDListType.PolicyIDList());
        messageBody.getPolicyIDList().getID().add(policyId);

        String requestXml = convertToXml(request, SpecialPolicyDetailSearchRequestType.class);
        logger.debug(requestXml);
        //System.out.println(requestXml);

        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_SpecialPolicyDetail, null);
        logger.debug(responseXml);
        //System.out.println(responseXml);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        return convertXmlTo(responseXml, SpecialPolicyDetailSearchResponseType.class);
    }

    /**
     * 新增加一个新的特殊政策
     * @param username
     * @param password
     * @param specialPolicyDetail
     * @return
     */
    public SpecialPolicyAddResponseType createSpecialPolicy(String username, String password, final String md5password, SpecialPolicyDetailType specialPolicyDetail) {
        List<SpecialPolicyDetailType> list = new ArrayList<SpecialPolicyDetailType>();
        list.add(specialPolicyDetail);

        return createSpecialPolicy(username, password, md5password, list);
    }

    public SpecialPolicyAddResponseType createSpecialPolicy(String username, String password, String md5password, List<SpecialPolicyDetailType> specialPolicyDetail) {
        SpecialPolicyAddRequestType request = new SpecialPolicyAddRequestType();

        request.setMessageHead(createMessageHeadType(username, password, md5password));

        SpecialPolicyAddRequestType.MessageBody messageBody = new SpecialPolicyAddRequestType.MessageBody();
        request.setMessageBody(messageBody);

        messageBody.setPolicyList(new SpecialPolicyAddRequestType.MessageBody.PolicyList());
        messageBody.getPolicyList().getPolicy().addAll(specialPolicyDetail);

        String requestXml = convertToXml(request, SpecialPolicyAddRequestType.class);

        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_SpecialPolicyAdd, null);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        return convertXmlTo(responseXml, SpecialPolicyAddResponseType.class);
    }


    public String searchLowPricePolicyList0(final String username, final String password, final String md5password, final String dport, final String aport, final Date ddate0, final Date ddate1, final String carrier, final String subclass, final int policyType) {
        return searchLowPricePolicyList0(username, password, md5password, dport, aport, ddate0, ddate1, carrier, subclass, policyType, 0, null);
    }

    /**
     * 3.4.1	低价政策列表查询
     * 注意：查询请求结果来源于缓存，因此和数据库中的实时数据会有几秒到几分钟不等的延时。请求次数限制为2000次/分钟。
     * @return
     */
    public String searchLowPricePolicyList0(final String username, final String password, final String md5password, final String dport, final String aport, final Date ddate0, final Date ddate1, final String carrier, final String subclass, final int policyType, final int realTimeData, final String productType) {
        LowPricePolicyListRequestType request = new LowPricePolicyListRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        messageHead.setRequestGUID(UUID.randomUUID().toString());

        request.setMessageHead(messageHead);

        LowPricePolicyListRequestType.MessageBody messageBody = new LowPricePolicyListRequestType.MessageBody();
        request.setMessageBody(messageBody);

        messageBody.setSearchCondition(new LowPricePolicySearchConditionType());

        messageBody.getSearchCondition().setDepartPort(dport);
        messageBody.getSearchCondition().setArrivePort(aport);
        String strSearchParam = dport + aport + "," + DateUtil.formatDate(ddate0, "yyyy-MM-dd");

        XMLGregorianCalendar xt = DateUtil.convertDateToXMLGregorianCalendar(ddate0);
        messageBody.getSearchCondition().setEffectDate(xt);

        if (ddate1 != null) {
            strSearchParam += "," + DateUtil.formatDate(ddate1, "yyyy-MM-dd");
            xt = DateUtil.convertDateToXMLGregorianCalendar(ddate1);
            messageBody.getSearchCondition().setExipryDate(xt);
        }

        if (carrier != null) {
            strSearchParam += "," + carrier;
            messageBody.getSearchCondition().setAirLine(carrier);
        }
        if (subclass != null) {
            strSearchParam += "," + subclass;
            messageBody.getSearchCondition().setGoSubClass(subclass);
        }

        if (realTimeData == 1) messageBody.getSearchCondition().setIsRealTimeData("TRUE");

//        logger.info(strSearchParam);

        if (policyType == Constant.POLICY_TYPE_NORMAL) {
            //ctrip common policy
            messageBody.getSearchCondition().setTradePolicyType("RAWPOLICY");
        } else if (policyType == Constant.POLICY_TYPE_SPECIAL) {
            //ctrip special policy
            messageBody.getSearchCondition().setTradePolicyType("SPECIALPOLICY");
        } else if (policyType == Constant.ALL_POLICY_TYPE) {
            messageBody.getSearchCondition().setTradePolicyType("ALL");
        }

        //产品类型
        if (productType != null) {
            LowPricePolicySearchConditionType.ShareProductTypeList productTypeList = new LowPricePolicySearchConditionType.ShareProductTypeList();
            messageBody.getSearchCondition().setShareProductTypeList(productTypeList);

            productTypeList.getItem().add(ShareProductType.fromValue(productType));
        }

        String requestXml = convertToXml(request, LowPricePolicyListRequestType.class);
        String responseXml = HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_LowPricePolicyList, null);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        return responseXml;
    }

    public List<LowPricePolicyListType> searchLowPricePolicyList(final String username, final String password, final String md5password, final String dport, final String aport, final Date ddate0, final Date ddate1, final String carrier, final String subclass, final int policyType) {
        return searchLowPricePolicyList(username, password, md5password, dport, aport, ddate0, ddate1, carrier, subclass, policyType, 0, null);
    }

    /**
     * 低价政策查询列表
     * @param username 接口用户名
     * @param password 接口密码
     * @param md5password 接口 md5 密码
     * @param dport 出发机场
     * @param aport 到达机场
     * @param ddate0 开始日期
     * @param ddate1 截止日期
     * @param carrier 航司
     * @param subclass 舱位
     * @param policyType 政策类型
     * @param realTimeData 是否实时数据
     * @param productType 产品类型
     * @return
     */
    public List<LowPricePolicyListType> searchLowPricePolicyList(final String username, final String password, final String md5password, final String dport, final String aport, final Date ddate0, final Date ddate1, final String carrier, final String subclass, final int policyType, final int realTimeData, final String productType) {
        String responseXml = searchLowPricePolicyList0(username, password, md5password, dport, aport, ddate0, ddate1, carrier, subclass, policyType, realTimeData, productType);

        List<LowPricePolicyListType> results = convertSearchLowPricePolicyListXml2Obj(responseXml);

        return results == null ? new ArrayList<>() : results;
    }

    /**
     * 将XML转换成需要的对象.
     * @param xml
     * @return
     */
    public List<LowPricePolicyListType> convertSearchLowPricePolicyListXml2Obj(String xml) {
        List<LowPricePolicyListType> results = null;

        LowPricePolicyListResponseType response = convertXmlTo(xml, LowPricePolicyListResponseType.class);

        if (response != null ) {
            int total = response.getTradeResult().getPolicyList().getPolicy().size();
            logger.debug("Total Count: " + total);

            if (response.getTradeResult().getPolicyList().getPolicy().size() > 0) {
                results = response.getTradeResult().getPolicyList().getPolicy();
            }
        }

        return results == null ? new ArrayList<>() : results;
    }

    /**
     * 有价格和有效性以外的东西需要修改时，用此方法。
     * @param username
     * @param password
     * @param policyId
     * @param flightNo
     * @return
     */
    public int updateSpecialPolicy(final String username, final String password, final String md5password, final long policyId, final Date effectDate, final Date expiryDate, final String days, final  String subclass, final boolean isCanSale, final String flightNo) {

        int retCode = 0;

        SpecialPolicyChangeRequestType request = new SpecialPolicyChangeRequestType();
        request.setMessageHead(createMessageHeadType(username, password, md5password));

        //message body
        SpecialPolicyChangeRequestType.MessageBody messageBody = new SpecialPolicyChangeRequestType.MessageBody();
        request.setMessageBody(messageBody);
        messageBody.setPolicyList(new SpecialPolicyChangeRequestType.MessageBody.PolicyList());


        //要修改的policy的参数
        SpecialPolicyChangeType policy = new SpecialPolicyChangeType();
        messageBody.getPolicyList().getPolicy().add(policy);
        policy.setPolicyID(policyId);

        //GoFlightUnit
        SpecialPolicyFlightType flight = new SpecialPolicyFlightType();
        policy.setGoFlightUnit(flight);

        flight.setEffectDate(DateUtil.convertDateToXMLGregorianCalendar(effectDate));
        flight.setExpiryDate(DateUtil.convertDateToXMLGregorianCalendar(expiryDate));
        flight.setDays(days);
        flight.setSubClass(subclass);
        if (isCanSale)
            flight.setIsCanSale(IsValidType.T);
        else
            flight.setIsCanSale(IsValidType.F);
        flight.setRuleDetail(flightNo);

        String requestXml = convertToXml(request, SpecialPolicyChangeRequestType.class);
        System.out.println(requestXml);

        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_SpecialPolicyChange, null);
        System.out.println(responseXml);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }


        SpecialPolicyChangeResponseType response  = convertXmlTo(responseXml, SpecialPolicyChangeResponseType.class);

        if (response != null) {
            int successCount = response.getTradeResult().getResult().getSummary().getSuccessCount();
            int failedCount = response.getTradeResult().getResult().getSummary().getFailedCount();

            logger.info("(updateSpecialPolicyPrice) Response Status: " + response.getResponseStatus().getAck().value());
            logger.info("(updateSpecialPolicyPrice) Success count: " + successCount + ", Failed count: " + failedCount);
            if (failedCount > 0) {
                logger.info(responseXml);
                int errSize = response.getTradeResult().getErrorList().getError().size();
                if (errSize > 0) {
                    TradeErrorType tradeError = response.getTradeResult().getErrorList().getError().get(0);
                    logger.warn("ErrorCode: " +tradeError.getErrorCode());
                    logger.warn("ErrorMsg: " + tradeError.getErrorMessage() );

                    System.out.println(tradeError.getErrorCode());
                    System.out.println(tradeError.getErrorMessage());
                }
            }

            retCode = successCount;
        }

        return retCode;
    }

    /**
     * 普通政策更新返点
     * -4 表示该政策已经不存在
     * 1  表示更新成功
     * 0  表示不成功
     * @param policyId
     * @param returnPoint
     * @return
     */
    public int updateCommonPolicyPrice(final String username, final String password, final String md5password, long policyId, float returnPoint) {
        CommonPolicyChangePriceRequestType request = new CommonPolicyChangePriceRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        messageHead.setRequestGUID(UUID.randomUUID().toString());

        request.setMessageHead(messageHead);

        CommonPolicyChangePriceRequestType.MessageBody messageBody = new CommonPolicyChangePriceRequestType.MessageBody();
        request.setMessageBody(messageBody);
        messageBody.setPolicyList(new CommonPolicyChangePriceRequestType.MessageBody.PolicyList());


        CommonPolicyPriceChangeType policy = new CommonPolicyPriceChangeType();
        policy.setPolicyID(policyId);

        policy.setPriceUnit(new CommonPolicyPriceType());
        BigDecimal bd = BigDecimal.valueOf(returnPoint).setScale(2, BigDecimal.ROUND_HALF_UP);
        policy.getPriceUnit().setReturnPoint(bd);

        messageBody.getPolicyList().getPolicy().add(policy);

        String requestXml = convertToXml(request, CommonPolicyChangePriceRequestType.class);
        logger.debug(requestXml);

        String responseXml = HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_CommonPolicyChangePrice, null);
        logger.debug(responseXml);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        CommonPolicyChangePriceResponseType response = convertXmlTo(responseXml, CommonPolicyChangePriceResponseType.class);

        int successCount = response.getTradeResult().getResult().getSummary().getSuccessCount();
        int failedCount = response.getTradeResult().getResult().getSummary().getFailedCount();
        logger.info("Success count: " + successCount + ", Failed count: " + failedCount);
        if (failedCount == 1 && successCount == 0) {
//            logger.info("RequestXml: " + requestXml);
//            logger.info("ResponseXml: " + responseXml);

            if (response.getTradeResult().getErrorList().getError().size() == 1) {
                TradeErrorType errorType = response.getTradeResult().getErrorList().getError().get(0);
                logger.warn(errorType.getErrorCode() + " " + errorType.getErrorMessage());

                if (errorType.getErrorCode() == 81020092) successCount = -4;
            }

        }


        return successCount;
    }

    /**
     * 修改特殊政策的价格和有效性
     * @param username
     * @param password
     * @param policyId
     * @param newSetPrice
     * @param policyValid
     * @return
     */
    public int updateSpecialPolicyPrice(final String username, final String password, final String md5password, long policyId, Float newSetPrice, Boolean policyValid) {
        List<Long> policyIds = new ArrayList<>();
        policyIds.add(policyId);

        return execUpdateSpecialPolicyPriceAndValidStatus(username, password, md5password, policyIds, newSetPrice, policyValid);
    }

    /**
     * 修改特殊政策的价格和有效状态
     * @param username
     * @param password
     * @param md5password
     * @param policyIds policy id 列表
     * @param newSetPrice 新价格
     * @param policyValid 政策状态
     * @return
     */
    private int execUpdateSpecialPolicyPriceAndValidStatus(final String username, final String password, final String md5password, List<Long> policyIds, Float newSetPrice, Boolean policyValid) {
        int retCode = 0;

        List<SpecialPolicyPriceChangeType> changeList = new ArrayList<>();

        for(Long policyId: policyIds) {

            SpecialPolicyPriceChangeType priceChangeType = new SpecialPolicyPriceChangeType();

            priceChangeType.setPolicyID(policyId);
            if (newSetPrice != null) {
                priceChangeType.setPriceUnit(new SpecialPolicyPriceType());
                priceChangeType.getPriceUnit().setSetPrice(BigDecimal.valueOf(newSetPrice));
            }

            if (policyValid != null) {
                if (policyValid)
                    priceChangeType.setIsValid(IsValidType.T);
                else
                    priceChangeType.setIsValid(IsValidType.F);
            }

            changeList.add(priceChangeType);
        }

        SpecialPolicyChangePriceResponseType response  = updateSpecialPolicyPrice(username, password, md5password, changeList);

        if (response != null) {
            try {
                if (response.getTradeResult().getResult() != null) {
                    int successCount = response.getTradeResult().getResult().getSummary().getSuccessCount();
                    int failedCount = response.getTradeResult().getResult().getSummary().getFailedCount();

                    if (successCount > 0) {
                        retCode = successCount;
                    } else if (failedCount > 0 && successCount == 0) {
                        logger.info("(updateSpecialPolicyPrice) Failed count: " + failedCount);

                        retCode = getResponseRetCode(retCode, response);
                    }
                } else if (response.getTradeResult().getErrorList() != null){
                    retCode = getResponseRetCode(retCode, response);
                }
            } catch (Exception ex) {
                logger.error(ex.getMessage());
            }
        }

        return retCode;
    }

    private int getResponseRetCode(int retCode, SpecialPolicyChangePriceResponseType response) {
        String remark = response.getTradeResult().getErrorList().getError().get(0).getErrorCode() + ","
                + response.getTradeResult().getErrorList().getError().get(0).getErrorMessage();
        retCode = -response.getTradeResult().getErrorList().getError().get(0).getErrorCode();
        logger.info(remark);
        return retCode;
    }


    /**
     * 修改指定政策的有效状态
     * @param username
     * @param password
     * @param md5password
     * @param policyId
     * @param policyValid
     * @return
     */
    public JsonResult updateSpecialPolicyValidStatus(String username, String password, String md5password, long policyId, Boolean policyValid) {
        int retCode = this.updateSpecialPolicyPrice(username, password, md5password, policyId, null, policyValid);

        return JsonResult.createJsonResult(retCode);
    }

    /**
     * 修改指定航线的特殊政策的状态
     * @param username
     * @param password
     * @param md5password
     * @param dport
     * @param aport
     * @param carrier
     * @param policyValid
     * @return
     */
    public JsonResult updateSpecialPoliciesValidStatus(final String username, final String password, final String md5password,
                                                       final String dport, final String aport, final String carrier, final Boolean policyValid) {
        SearchPolicyCriteria sc = new SearchPolicyCriteria();
        sc.setDeparturePort(dport);
        sc.setArrivalPort(aport);
        sc.setCarrier(carrier);
        sc.setPageSize(10000);

        SpecialPolicySummaryResponseType response = this.searchSpecialPolicySummary(username, password, md5password, sc);
        final int totalCount = response.getTradeResult().getSearchResult().getTotalCount();

        List<Long> policyIds = new ArrayList<>();
        for(SpecialPolicySummaryDataType policyInfo: response.getTradeResult().getSearchResult().getPolicyList().getPolicy()) {
            policyIds.add(policyInfo.getPolicyID());
        }

        if (policyIds.size() < 1) return JsonResult.createJsonResult(-1, "未找到需要修改的特殊政策");

        return this.updateSpecialPolicyValidStatus(username, password, md5password, policyIds, policyValid);
    }

    /**
     * 修改多个特殊政策的有效状态
     * @param username
     * @param password
     * @param md5password
     * @param policyIds
     * @param policyValid
     * @return
     */
    public JsonResult updateSpecialPolicyValidStatus(String username, String password, String md5password, List<Long> policyIds, Boolean policyValid) {
        int retCode = this.execUpdateSpecialPolicyPriceAndValidStatus(username, password, md5password, policyIds, null, policyValid);
        return JsonResult.createJsonResult(retCode);
    }

    /**
     * 批量修改政策价格
     * @param username
     * @param password
     * @param md5password
     * @param changeList
     * @return
     */
    public SpecialPolicyChangePriceResponseType updateSpecialPolicyPrice(String username, String password, String md5password, List<SpecialPolicyPriceChangeType> changeList) {
        SpecialPolicyChangePriceRequestType request = new SpecialPolicyChangePriceRequestType();
        request.setMessageHead(createMessageHeadType(username, password, md5password));

        SpecialPolicyChangePriceRequestType.MessageBody messageBody = new SpecialPolicyChangePriceRequestType.MessageBody();
        request.setMessageBody(messageBody);

        messageBody.setPolicyList(new SpecialPolicyChangePriceRequestType.MessageBody.PolicyList());

        for(SpecialPolicyPriceChangeType policy: changeList)
            messageBody.getPolicyList().getPolicy().add(policy);

        String requestXml = convertToXml(request, SpecialPolicyChangePriceRequestType.class);
        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_SpecialPolicyChangePrice, null);

        System.out.println(requestXml);
        System.out.println(responseXml);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        return convertXmlTo(responseXml, SpecialPolicyChangePriceResponseType.class);
    }

    /**
     * 根据政策id， 删除远端的一个政策
     * @param policyId
     * @return
     */
    public  ApiOpResult  deleteSpecialPolicy(final String username, final String password, final String md5password, long policyId) {
        List<Long> ids = new ArrayList<>();
        ids.add(policyId);

        return deleteSpecialPolicy(username, password, md5password, ids);
    }

    @Override
    public ApiOpResult deleteSpecialPolicy(final String username, final String password, final String md5password, final List<Long> ids) {
        ApiOpResult result = new ApiOpResult();

        int retCode = 0;

        SpecialPolicyDeleteRequestType request = new SpecialPolicyDeleteRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        messageHead.setRequestGUID(UUID.randomUUID().toString());

        request.setMessageHead(messageHead);

        SpecialPolicyDeleteRequestType.MessageBody messageBody = new SpecialPolicyDeleteRequestType.MessageBody();
        request.setMessageBody(messageBody);

        messageBody.setDeleteType("ByID");
        messageBody.setPolicyIDList(new SpecialPolicyDeleteRequestType.MessageBody.PolicyIDList());
        messageBody.getPolicyIDList().getID().addAll(ids);


        String requestXml= convertToXml(request, SpecialPolicyDeleteRequestType.class);
        logger.debug(requestXml);

        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_SpecialPolicyDelete, null);
        logger.debug(responseXml);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        SpecialPolicyDeleteResponseType response  = convertXmlTo(responseXml, SpecialPolicyDeleteResponseType.class);

        if (response != null) {
            if (response.getTradeResult().getResult() != null) {
                //logger.info("Response Status: " + response.getResponseStatus().getAck().value());
                int successCount = response.getTradeResult().getResult().getSummary().getSuccessCount();
                int failedCount = response.getTradeResult().getResult().getSummary().getFailedCount();
                if (successCount == 0 || successCount != ids.size()) {
                    logger.info("deleteSpecialPolicy: Success count= " + successCount + ", Failed count= " + failedCount);
                    logger.info(responseXml);
                }

                result.setSuccessCount(successCount);
                result.setFailCount(failedCount);
                result.setFailedList(response.getTradeResult().getResult().getFailedList().getID());
            } else {
                for (TradeErrorType error : response.getTradeResult().getErrorList().getError()) {
                    logger.info("ErrorCode: " + error.getErrorCode() + ", ErrorMessage: " + error.getErrorMessage());
                }
            }
        }

        return result;
    }

    /**
     * 删除远端一条指定政策
     * @param policyId
     * @return
     */
    public int deleteCommonPolicy(final String username, final String password, final String md5password, long policyId) {
        int retCode = 0;

        CommonPolicyDeleteRequestType request = new CommonPolicyDeleteRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        messageHead.setRequestGUID(UUID.randomUUID().toString());
        request.setMessageHead(messageHead);

        CommonPolicyDeleteRequestType.MessageBody messageBody = new CommonPolicyDeleteRequestType.MessageBody();
        request.setMessageBody(messageBody);

        messageBody.setDeleteType("ByID");
        messageBody.setPolicyIDList(new CommonPolicyDeleteRequestType.MessageBody.PolicyIDList());
        messageBody.getPolicyIDList().getID().add(policyId);

        String requestXml= convertToXml(request, CommonPolicyDeleteRequestType.class);
        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_CommonPolicyDelete, null);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        CommonPolicyDeleteResponseType response  = convertXmlTo(responseXml, CommonPolicyDeleteResponseType.class);

        if (response != null) {
            logger.info("Response Status: " + response.getResponseStatus().getAck().value());
            if (response.getTradeResult().getResult() != null) {
                int successCount = response.getTradeResult().getResult().getSummary().getSuccessCount();
                int failedCount = response.getTradeResult().getResult().getSummary().getFailedCount();
                logger.info("Success count: " + successCount + ", Failed count: " + failedCount);

                retCode = successCount;
            } else {
                for(TradeErrorType error: response.getTradeResult().getErrorList().getError()) {
                    System.out.println("ErrorCode: " + error.getErrorCode() + ", ErrorMessage: " + error.getErrorMessage());
                }
            }
        }

        return retCode;
    }

    public List<Long> searchCommonPolicyIdList(final String username, final String password, final String md5password) {
        List<Long> idList = new ArrayList<Long>();

        CommonPolicyIDListRequestType request = new CommonPolicyIDListRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        messageHead.setRequestGUID(UUID.randomUUID().toString());

        request.setMessageHead(messageHead);

        CommonPolicyIDListRequestType.MessageBody messageBody = new CommonPolicyIDListRequestType.MessageBody();
        request.setMessageBody(messageBody);
        request.getMessageBody().setSearchType(IDListSearchType.BY_CONDITION);
        request.getMessageBody().setStartIndex(0);
        request.getMessageBody().setPageSize(1000000);

        String result = convertToXml(request, CommonPolicyIDListRequestType.class);

        String responseXml = HttpAccessAdapter.SendTradeQuickApiRequest(result, API_CommonPolicyIDList, null);
        int idx = responseXml.indexOf("<");
        if (idx > 0)
            responseXml = responseXml.substring(idx);

        CommonPolicyIDListResponseType response = convertXmlTo(responseXml, CommonPolicyIDListResponseType.class);

        if (response.getTradeResult().getErrorList().getError().size() > 0) {
            for(TradeErrorType errorType: response.getTradeResult().getErrorList().getError())
                logger.warn("ErrorCode: " + errorType.getErrorCode() + ", ErrorMsg: " + errorType.getErrorMessage());
        }

        int total = response.getTradeResult().getSearchResult().getTotalCount();
        if (total > 0) {
            for (PolicySearchType policy : response.getTradeResult().getSearchResult().getPolicyList().getPolicy())
                idList.add(policy.getID());
        }

        return idList;
    }

    public String searchPataSummary(final String username, final String password, final String md5password) {
        List<Long> idList = new ArrayList<Long>();

        PataSummarySearchRequestType request = new PataSummarySearchRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        messageHead.setRequestGUID(UUID.randomUUID().toString());

        request.setMessageHead(messageHead);

        PataSummarySearchRequestType.MessageBody messageBody = new PataSummarySearchRequestType.MessageBody();
        request.setMessageBody(messageBody);

        PataSummarySearchConditionType searchCondition = new PataSummarySearchConditionType();
        searchCondition.setFlightWay(FlightWayType.S);
        request.getMessageBody().setSearchCondition(searchCondition); // .setSearchType(IDListSearchType.BY_CONDITION);
        request.getMessageBody().setStartIndex(0);
        request.getMessageBody().setPageSize(100000);

        String requestXml = convertToXml(request, PataSummarySearchRequestType.class);

        String responseXml = HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_PataSummarySearch, null);
        int idx = responseXml.indexOf("<");
        if (idx > 0)
            responseXml = responseXml.substring(idx);

        PataSummarySearchResponseType response = convertXmlTo(responseXml, PataSummarySearchResponseType.class);

//        if (response.getTradeResult().getErrorList().getError().size() > 0) {
//            for(TradeErrorType errorType: response.getTradeResult().getErrorList().getError())
//                logger.warn("ErrorCode: " + errorType.getErrorCode() + ", ErrorMsg: " + errorType.getErrorMessage());
//        }
//
//        int total = response.getTradeResult().getSearchResult().getTotalCount();
//        if (total > 0) {
//            for (PolicySearchType policy : response.getTradeResult().getSearchResult().getPolicyList().getPolicy())
//                idList.add(policy.getID());
//        }

        System.out.println(requestXml);
        System.out.println(responseXml);

        return responseXml;
    }

    public SpecialPolicyDeleteResponseType deleteSpecialPolicyByPolicyCode(final String username, final String password, final String md5password, final String policyCode, final boolean isFuzzy) {
        SpecialPolicyDeleteRequestType request = new SpecialPolicyDeleteRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        messageHead.setRequestGUID(UUID.randomUUID().toString());

        request.setMessageHead(messageHead);

        SpecialPolicyDeleteRequestType.MessageBody messageBody = new SpecialPolicyDeleteRequestType.MessageBody();
        request.setMessageBody(messageBody);

        messageBody.setDeleteType("ByCode");
        messageBody.setPolicyCodeList(new SpecialPolicyDeleteRequestType.MessageBody.PolicyCodeList());
        messageBody.getPolicyCodeList().getCode().add(policyCode);

        if (isFuzzy) messageBody.setIsFuzzyMatch(IsValidType.T);
        else messageBody.setIsFuzzyMatch(IsValidType.F);


        String requestXml= convertToXml(request, SpecialPolicyDeleteRequestType.class);
        if (this.outputXml) {
            System.out.println(requestXml);
        }

        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_SpecialPolicyDelete, null);
        if (this.outputXml) {
            System.out.println(responseXml);
        }

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        return convertXmlTo(responseXml, SpecialPolicyDeleteResponseType.class);
    }

    @Override
    public String searchFdPolicy(String username, String password, String md5password, String dcity, String acity) {
        FdPolicySearchRequestType request = new FdPolicySearchRequestType();

        MessageHeadType messageHead = new MessageHeadType();
        messageHead.setUserInfo(createUserInfo(username, password, md5password));
        messageHead.setRequestGUID(UUID.randomUUID().toString());

        request.setMessageHead(messageHead);

        FdPolicySearchRequestType.MessageBody messageBody = new FdPolicySearchRequestType.MessageBody();
        request.setMessageBody(messageBody);

        DCityACityType dCityACityType = new DCityACityType();
        dCityACityType.setDcity(dcity);
        dCityACityType.setAcity(acity);

        messageBody.getdCityACityList().getDCityACityTypes().add(dCityACityType);



        String requestXml= convertToXml(request, FdPolicySearchRequestType.class);

        String responseXml =  HttpAccessAdapter.SendTradeQuickApiRequest(requestXml, API_FdPolicySearch, null);

        int idx = responseXml.indexOf("<");
        if (idx > 0) {
            responseXml = responseXml.substring(idx);
        }

        return responseXml;
    }

    @Override
    public FdPolicySearchResponseType convertXml2FdPolicySearchResponseType(String xml) {
        return convertXmlTo(xml, FdPolicySearchResponseType.class);
    }

    private <T>T convertXmlTo(String xml, Class<T> c) {
        if (xml == null || xml.length() == 0) return null;

        T response = null;
        try {
            JAXBContext jc = JAXBContext.newInstance(c);
            Unmarshaller m = jc.createUnmarshaller();
            Object obj = m.unmarshal(new StringReader(xml));

            if (obj.getClass() == JAXBElement.class) obj = ((JAXBElement)obj).getValue();

            response= (T) obj;

        } catch (JAXBException e) {
            logger.error(e.getMessage());
            logger.error("xml: " + xml);
        }

        return response;
    }

}
